//////////////////////////////////////////////////////////////////////////////////   
// 合并功能：OLED显示2个摇杆的X/Y轴数据（适配Arduino Nano）
// 引脚说明：
// - OLED：SDA=6、SCL=7、RES=A3、VCC=5V、GND=GND
// - 摇杆1：X轴=A5、Y轴=A4（模拟输入，无需额外上拉）
// - 摇杆2：X轴=A2、Y轴=A1（模拟输入，无需额外上拉）
// OLED地址：默认0x3C（若屏幕不亮，可改为0x3D）
//////////////////////////////////////////////////////////////////////////////////
#include "oledfont.h"
#include <SoftwareWire.h>  // 软件I2C库（需提前安装）
//测试完成可以使用 
// -------------------------- 【全局引脚配置区】 --------------------------
// OLED引脚（软件I2C，可修改）
#define OLED_SDA   6     // OLED数据引脚（SDA）
#define OLED_SCL   7     // OLED时钟引脚（SCL）
#define OLED_RES   A3    // OLED复位引脚（RES）
#define OLED_ADDR  0x3C  // OLED I2C地址（常见：0x3C / 0x3D）

// 摇杆引脚（模拟输入，可修改）
#define JOY1_X     A5    // 摇杆1 X轴（模拟引脚）
#define JOY1_Y     A4    // 摇杆1 Y轴（模拟引脚）
#define JOY2_X     A2    // 摇杆2 X轴（模拟引脚）
#define JOY2_Y     A1    // 摇杆2 Y轴（模拟引脚）
// --------------------------------------------------------------------------

// -------------------------- 【类型定义与全局变量】 --------------------------
// 补充无冲突的类型定义
typedef unsigned char  u8;
typedef unsigned long  u32;

// 软件I2C对象初始化（指定SDA/SCL引脚）
SoftwareWire myWire(OLED_SDA, OLED_SCL);

// OLED命令/数据标志
#define OLED_CMD  0  // 写命令
#define OLED_DATA 1 // 写数据

// 摇杆数据存储变量（全局变量，方便显示函数调用）
int joy1_X_val, joy1_Y_val;  // 摇杆1的X/Y轴数值（0~1023）
int joy2_X_val, joy2_Y_val;  // 摇杆2的X/Y轴数值（0~1023）
// --------------------------------------------------------------------------


// -------------------------- 【OLED核心功能函数】 --------------------------
// 复位引脚操作宏
#define OLED_RES_Clr()  digitalWrite(OLED_RES, LOW)
#define OLED_RES_Set()  digitalWrite(OLED_RES, HIGH)

// 发送1字节数据/命令
void OLED_WR_Byte(u8 dat, u8 mode) {
  myWire.beginTransmission(OLED_ADDR);
  mode ? myWire.write(0x40) : myWire.write(0x00); // 数据=0x40，命令=0x00
  myWire.write(dat);
  myWire.endTransmission();
}

// 设置OLED显示坐标（x:0~127，y:0~7，对应8个页）
void OLED_Set_Pos(u8 x, u8 y) { 
  OLED_WR_Byte(0xB0 + y, OLED_CMD);                  // 页地址（0~7）
  OLED_WR_Byte(((x & 0xF0) >> 4) | 0x10, OLED_CMD);  // 列高4位
  OLED_WR_Byte((x & 0x0F), OLED_CMD);                // 列低4位
}

// 清屏（全屏变黑）
void OLED_Clear(void) {  
  u8 i, n;       
  for (i = 0; i < 8; i++) {  // 遍历8个页
    OLED_WR_Byte(0xB0 + i, OLED_CMD);
    OLED_WR_Byte(0x00, OLED_CMD);
    OLED_WR_Byte(0x10, OLED_CMD);   
    for (n = 0; n < 128; n++) OLED_WR_Byte(0, OLED_DATA); 
  } 
}

// 显示字符串（x:起始列，y:起始页，chr:字符串，sizey:字体大小8/16）
void OLED_ShowString(u8 x, u8 y, const char *chr, u8 sizey) {
  u8 j = 0;
  while (chr[j] != '\0') {   
    OLED_ShowChar(x, y, chr[j++], sizey);
    x += (sizey == 8) ? 6 : 8; // 6x8字体占6列，8x16占8列
  }
}

// 显示单个字符（x:列，y:页，chr:字符，sizey:字体大小8/16）
void OLED_ShowChar(u8 x, u8 y, const u8 chr, u8 sizey) {       
  u8 c = chr - ' ', sizex = sizey / 2, temp;
  unsigned int i = 0, size1 = (sizey == 8) ? 6 : 32; // 6x8=6字节，8x16=32字节
  
  OLED_Set_Pos(x, y);
  for (i = 0; i < size1; i++) {
    if (i % sizex == 0 && sizey != 8) OLED_Set_Pos(x, y++); // 8x16字体跨2页
    // 从字体库读取数据（需oledfont.h支持asc2_0806/asc2_1608数组）
    temp = (sizey == 8) ? pgm_read_byte(&asc2_0806[c][i]) : pgm_read_byte(&asc2_1608[c][i]);
    OLED_WR_Byte(temp, OLED_DATA);
  }
}

void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len, u8 sizey) {           
  u8 t, temp, m = (sizey == 8) ? 2 : 0;
  // u8 enshow = 0; // 注释掉，关闭前导零跳过逻辑
  for (t = 0; t < len; t++) {
    temp = (num / oled_pow(10, len - t - 1)) % 10;
    // if (enshow == 0 && t < (len - 1)) { // 注释掉
    //   if (temp == 0) {
    //     OLED_ShowChar(x + (sizey / 2 + m) * t, y, ' ', sizey);
    //     continue;
    //   } else enshow = 1;
    // }
    OLED_ShowChar(x + (sizey / 2 + m) * t, y, temp + '0', sizey); // 强制显示所有位
  }
}

// 幂运算（用于数字显示时提取每一位）
u32 oled_pow(u8 m, u8 n) {
  u32 result = 1;  
  while (n--) result *= m;    
  return result;
}

// OLED初始化（硬件初始化+显示配置）
void OLED_Init(void) {
  pinMode(OLED_RES, OUTPUT);  // 复位引脚设为输出
  myWire.begin();             // 软件I2C初始化（主机模式）
  
  // OLED复位流程
  OLED_RES_Clr();
  delay(200);
  OLED_RES_Set();
  
  // SSD1306控制器初始化命令（固定流程）
  OLED_WR_Byte(0xAE, OLED_CMD); // 关闭显示
  OLED_WR_Byte(0x00, OLED_CMD); // 低列地址
  OLED_WR_Byte(0x10, OLED_CMD); // 高列地址
  OLED_WR_Byte(0x40, OLED_CMD); // 显示起始行
  OLED_WR_Byte(0x81, OLED_CMD); // 对比度控制
  OLED_WR_Byte(0xCF, OLED_CMD); // 对比度值（0x00~0xFF）
  OLED_WR_Byte(0xA1, OLED_CMD); // 列扫描方向（正常）
  OLED_WR_Byte(0xC8, OLED_CMD); // 行扫描方向（正常）
  OLED_WR_Byte(0xA6, OLED_CMD); // 正常显示（非反色）
  OLED_WR_Byte(0xA8, OLED_CMD); // 多路复用比
  OLED_WR_Byte(0x3F, OLED_CMD); // 1/64 duty（适配128x64屏幕）
  OLED_WR_Byte(0xD3, OLED_CMD); // 显示偏移
  OLED_WR_Byte(0x00, OLED_CMD); // 无偏移
  OLED_WR_Byte(0xD5, OLED_CMD); // 时钟分频
  OLED_WR_Byte(0x80, OLED_CMD); // 100帧/秒
  OLED_WR_Byte(0xD9, OLED_CMD); // 预充电周期
  OLED_WR_Byte(0xF1, OLED_CMD); // 预充电15时钟
  OLED_WR_Byte(0xDA, OLED_CMD); // COM引脚配置
  OLED_WR_Byte(0x12, OLED_CMD); // 适配128x64
  OLED_WR_Byte(0xDB, OLED_CMD); // VCOMH电压
  OLED_WR_Byte(0x40, OLED_CMD); // 电压等级
  OLED_WR_Byte(0x20, OLED_CMD); // 页寻址模式
  OLED_WR_Byte(0x02, OLED_CMD); // 页模式
  OLED_WR_Byte(0x8D, OLED_CMD); // 电荷泵使能
  OLED_WR_Byte(0x14, OLED_CMD); // 使能电荷泵
  OLED_WR_Byte(0xA4, OLED_CMD); // 只显示有效像素
  OLED_WR_Byte(0xA6, OLED_CMD); // 非反色
  OLED_Clear();                 // 清屏
  OLED_WR_Byte(0xAF, OLED_CMD); // 开启显示
}
// --------------------------------------------------------------------------


// -------------------------- 【主函数（setup+loop）】 --------------------------
void setup() {
  OLED_Init();          // 1. 初始化OLED
  Serial.begin(9600);   // 2. 初始化串口（可选，用于调试）
  

  delay(1000);          // 显示1秒后清屏，准备显示实时数据
  OLED_Clear();
}

void loop() {
  // 1. 读取摇杆数据（模拟输入范围：0~1023）
  joy1_X_val = analogRead(JOY1_X);
  joy1_Y_val = analogRead(JOY1_Y);
  joy2_X_val = analogRead(JOY2_X);
  joy2_Y_val = analogRead(JOY2_Y);

  // 2. OLED显示摇杆数据（分4行显示，字体16x8，清晰易读）
  // 第0页：显示摇杆1 X轴（左）和Y轴（右）
OLED_ShowString(10, 0, "1X:", 8);  // 字符串占 5×8=40 列
OLED_ShowNum(60, 0, joy1_X_val, 4, 8);  // 数字占 4×8=32 列，x=60 避免重叠

// 摇杆1 Y轴：页 1（y=1），列从 10 开始（下一页，避免和上一行重叠）
OLED_ShowString(10, 1, "1Y:", 8);  
OLED_ShowNum(60, 1, joy1_Y_val, 4, 8); 
  
  // 第2页：显示摇杆2 X轴（左）和Y轴（右）
  OLED_ShowString(10, 2, "2X", 8);    // 文字标注（X轴）
  OLED_ShowNum(60, 2, joy2_X_val, 4, 8);  // 数值
  OLED_ShowString(10, 3, "2Y", 8);        // 文字标注（Y轴）
  OLED_ShowNum(60, 3, joy2_Y_val, 4, 8); // 数值

  // 3. 串口打印数据（可选，用于调试对比）
  
  Serial.print("Joy1: X="); Serial.print(joy1_X_val);
  Serial.print(" Y="); Serial.print(joy1_Y_val);
  Serial.print(" | Joy2: X="); Serial.print(joy2_X_val);
  Serial.print(" Y="); Serial.println(joy2_Y_val);
 
  // 4. 延迟100ms（平衡更新速度与屏幕稳定性，避免闪烁）
  delay(100);
}
